#include <sys/types.h>
#include <unistd.h>

#include <stdio.h>

#include <sched.h>

#include <stdlib.h>
#include <signal.h>

#include <sys/time.h>

#include "rdtsc.h"
#define get_cycles rdtsc


#define US 50
#define MAX 2000

static unsigned long int pin[MAX], pout[MAX];
static unsigned long long int scale = SCALE;
static int Q,T,D;
static int sleeptime;
static int relative;

static void print_results (int signo)
{
  int points;

  fprintf(stderr, "Results:\n");
  for (points = 1; points < MAX; points++) {
    if ((pin[points] != 0) && (pout[points] != 0)) {
      printf("%lu --- %lu\t\t(Distance: %lu\tSize:%lu)\n",
		      pin[points], pout[points],
		      pin[points] - pout[points - 1],
		      pout[points] - pin[points]);
    }
  }

  fprintf(stderr,"%d:%d is over.\n",Q,T);
  exit(0);
}

static void args_parse(int argc, char *argv[])
{
  int v;

  /* Default parameters */
  Q = 300000;  /* Budget */
  T = 1000000; /* Period */
  D = 20;      /* Seconds before stop the simulation */
  sleeptime = 3;

  while ((v = getopt(argc, argv, "q:t:l:s:r")) != -1) {
    switch (v) {
      case 'q':
        Q = atoi(optarg);
        break;
      case 't':
        T = atoi(optarg);
        break;
      case 'l':
        D = atoi(optarg);
        break;
      case 's':
        sleeptime = atoi(optarg);
        break;
      case 'r':
        relative = 1;
      default:
        fprintf(stderr, "Exiting because of illegal option!\n");
        
        exit(-1);
    }
  }
}

int main(int argc, char *argv[])
{
  unsigned long long int k, t1, t, told, thr;
  int points;
  struct sched_param sp;
  int res;

  struct itimerval it1, it2; 
  struct sigaction s1,s2;

  args_parse(argc, argv);
 
  /* Timer to stop the program */
  it1.it_value.tv_usec = 0;
  it1.it_value.tv_sec = D;
  it1.it_interval.tv_usec = 0;
  it1.it_interval.tv_sec = D;
  setitimer(ITIMER_REAL, &it1, &it2);
 
  s1.sa_handler = print_results;
  sigemptyset(&s1.sa_mask);
  s1.sa_flags = 0;
  sigaction(SIGALRM, &s1, &s2);

  sp.sched_priority = 0;
  sp.sched_ss_init_budget.tv_nsec = Q * 1000;
  sp.sched_ss_init_budget.tv_sec = 0;
  sp.sched_ss_repl_period.tv_nsec = T * 1000 ;
  sp.sched_ss_repl_period.tv_sec = 0 ;

  fprintf(stderr, "Setting scheduler (%u %u)\n", Q, T);
  res = sched_setscheduler(getpid(), SCHED_CBS, &sp);
  if (res < 0) {
    perror("Error in setscheduler!");
    exit(-1);
  }
  fprintf(stderr, "SetSched done!\n");
  points = 0;
  k = 0;

  if (relative) {
    t1 = get_cycles();
  } else {
    t1 = 0;
  }
  told = t1;
  thr = (US * SCALE);
  if (thr == 0) thr = 1;
  fprintf(stderr, "Threshold: %Lu\n", thr);

  fprintf(stderr, "Sleeping...\n");
  sleep(sleeptime);

  fprintf(stderr, "Going...\n");
  while (points < MAX - 1) {
    t = get_cycles();
    if ((t - told) > thr) {
      pout[points] = (told - t1) / scale;
      pin[++points] = (t - t1) / scale;
    }
    told = t;
  }
  print_results(0);
  return 0;
}
